Fix disc rescan not updating after swapping discs#13
Conversation
ScanDiscCdparanoia#scan() and ScanDiscCdinfo#scan() both had an early
return guard ('return true if @status == 'ok'') that prevented re-scanning
after the first successful scan. This meant swapping discs and selecting
'Scan drive for audio disc' would still show the old disc's data.
- Call restoreStatus() at the start of ScanDiscCdparanoia#scan() to
reset @status and @error before each scan.
- Set @status = nil at the start of ScanDiscCdinfo#scan() for the same
purpose.
- Fix existing scanDiscCdparanoia_spec.rb mock argument matching
(missing stopPatterns parameter).
- Add rescan-behavior tests for both scanners.
Code Review: PR #13 (fix-disc-rescan-cache)15 findings across 10 review angles — ranked by severity. 🔴 CRITICAL: Data Corruption on Rescan (3)
🟠 HIGH: Breaking API Changes (2)
No internal callers use the return value, but external library consumers will break. 🟡 MEDIUM: Architecture & Maintenance (5)
🟢 LOW: Test Coverage & Consistency (5)
Key InsightThe PR fixes rescan only for cdinfo and cdparanoia, but leaves cdcontrol with the exact same bug. This is an incomplete refactoring across similar implementations. Recommendations
|
|
I have investigated and addressed the HIGH/CRITICAL issues regarding the rescan cache and return values. Instead of manually resetting the state variables within each scanner class, I implemented a much safer approach: recreating the scanner instances upon each rescan from the caller side (
Regarding the return value contract ( Please review the latest commits. |
7cd9963 to
0ba31dc
Compare
0ba31dc to
58377a6
Compare
Code Review Results (max effort)Scope: +33/-4 lines, 7 files 🔴 1.
|
…sc Disc.new() instead PR #13's original approach modified 7 files to add scanner instance re-creation and @has_mock workaround inside Disc#scan. This left multiple stale-state issues (CalcFreedbID/CalcMusicbrainzID caches, @DataTracks accumulation, @firstAudioTrack freeze) that required per-variable resets. A simpler approach: make CliDisc#refreshDisc recreate the Disc instance on every rescan, exactly like GtkDisc and TUIDisc already do. This guarantees all sub-objects (Scanner, CalcFreedbID, CalcMusicbrainzID) start fresh without per-variable reset patches. Changes: - cliDisc.rb: refreshDisc now does @cd = Disc.new(); @cd.scan() - scanDiscCdparanoia.rb: restore 'return true if @status == 'ok'' guard - scanDiscCdinfo.rb: restore 'return true if @status == 'ok'' guard - scanDiscCdcontrol.rb: restore 'return true if @status == 'ok'' guard - disc.rb: revert @has_mock, @cdparanoia re-creation, @scanner/etc=nil - spec/cli/cliDisc_spec.rb: new test verifying Disc.new() on refresh - spec/disc/disc_spec.rb: revert 'When scanning again' test block - spec/disc/scanDiscCdinfo_spec.rb: revert trailing blank lines - spec/disc/scanDiscCdparanoia_spec.rb: revert trailing blank lines (any_args fix from PR #13 preserved as pre-existing bugfix)
Reworked approach: recreate Disc in CliDisc#refreshDisc instead of per-variable resetProblem with the previous approachPR #13 patched 7 files (scanner early-return removal,
Fixing each of these individually would scatter more per-variable resets across the codebase. Simplified fix: recreate Disc on refreshGTK ( One-line change in # before
def refreshDisc ; @cd.scan() ; end
# after
def refreshDisc
@cd = Disc.new()
@cd.scan()
endThis guarantees all sub-objects ( What this commit reverts vs preservesReverted (back to master state):
Preserved:
New:
|
Code Review (max effort)Summary: Tests: All 53 relevant tests PASS ✓ Findings4. [MEDIUM] @error not cleared after successful rescanIn No current production caller reads 5. [LOW] Object allocation churn on every rescanEach 6. [LOW] cliDisc_spec mock depends on exact Disc.new call countexpect(Disc).to receive(:new).and_return(first_disc, second_disc)Constructor consumes 7. [LOW] cdrdao background thread may be abandoned on rescan
[INFO] Design trade-off — scanner early-return guardThe This is safe as long as all rescans go through |
|
以下は今回のPR変更範囲外
以下は意図した動作で問題なし
結果としてレビューはOK |
Summary
Both
ScanDiscCdparanoia#scan()andScanDiscCdinfo#scan()had an early-return guard (return true if @status == 'ok') that prevented re-scanning after the first successful scan. Once@statuswas set to"'ok'", it was never reset, so swapping discs and selecting "2) Scan drive for audio disc" from the CLI menu would still show the old disc's track information.Root Cause
@statusis initialized tonilin the constructor and set to"'ok'"after a successful scan, but never reset afterward, causing every subsequent scan call to short-circuit immediately.Call Flow
ScanDiscCdparanoiaalready had arestoreStatusmethod (@status = nil; @error = nil) used insidewaitForDisc, but it was never called at the top ofscan().ScanDiscCdinfohad no such reset mechanism at all.Changes
lib/rubyripper/disc/scanDiscCdparanoia.rbrestoreStatus()at the start ofscan(). This resets@statusand@errorbefore every scan, ensuringcd-paranoia -vQactually runs each time.lib/rubyripper/disc/scanDiscCdinfo.rb@status = nilat the start ofscan(). Same effect: thecd-infocommand is executed every time instead of short-circuiting.spec/disc/scanDiscCdparanoia_spec.rbExecute#launchsignature was extended with astopPatternsparameter that the test mocks did not account for).scan()call re-executes the launch command.spec/disc/scanDiscCdinfo_spec.rbscan()call reflects a different disc result.Testing